package crmdna.client.member;

import static crmdna.common.OfyService.ofy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.googlecode.objectify.Work;

import crmdna.client.sequence.Sequence;
import crmdna.client.sequence.Sequence.SequenceType;
import crmdna.common.APIException;
import crmdna.common.APIResponse.Status;
import crmdna.common.Utils;

public class InteractionCore {
	
	public enum InteractionType {
		PHONE, EMAIL, FB, GOOGLEPLUS, SMS, FACETOFACE, WEBSITE, OTHER
	}
		
	public static class InteractionProp implements Comparable<InteractionProp> {
		public long interactionId;
		public Date timestamp;
		public String interaction;
		public InteractionType interactionType;
		public long userId;
		
		@Override
		public int compareTo(InteractionProp arg0) {
			return arg0.timestamp.compareTo(this.timestamp);
		}
	}
	
	private final static long MAX_INTERACTION_SIZE = 900 * 1024;
	
	static InteractionProp create(String namespace, String interaction, 
			InteractionType interactionType, Date timestamp, long userId) {
		
		if (null == timestamp)
			timestamp = new Date();
		
		ensureValid(interaction, interactionType, timestamp);
		
		InteractionEntity interactionEntity = new InteractionEntity();
		interactionEntity.interactionId = 
				Sequence.getNext(namespace, SequenceType.INTERACTION);
					
		interactionEntity.timestamp = timestamp;
		interactionEntity.interaction = interaction;
		interactionEntity.interactionType = interactionType;
		interactionEntity.userId = userId;
		
		ofy(namespace).save().entity(interactionEntity).now();
		return interactionEntity.toProp();
	}
	
	private static void ensureValid(String interaction, InteractionType interactionType, 
			Date timestamp) {
		
		if (null == interactionType)
			Utils.throwIncorrectSpecException("interactionType cannot be null");
		
		if ((null == interaction) || interaction.equals(""))
			Utils.throwIncorrectSpecException("interaction cannot be null or empty string");
				
		if (interaction.length() > MAX_INTERACTION_SIZE)
			Utils.throwIncorrectSpecException("interaction cannot be null or empty string");
		
		if (null == timestamp)
			Utils.throwIncorrectSpecException("timestamp cannot be null");		
	}
	
	static void delete(String namespace, long interactionId) {
		
		InteractionEntity interactionEntity = safeGet(namespace, interactionId);
		
		ofy(namespace).delete().entity(interactionEntity).now();		
	}
	
	static InteractionEntity safeGet(String namespace, long interactionId) {
		InteractionEntity interactionEntity =
				ofy(namespace).load().type(InteractionEntity.class).id(interactionId).get();
		
		if (null == interactionEntity)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
					"Interaction id [" + interactionId + "] does not exist");
		
		return interactionEntity;
	}
	
	static List<InteractionProp> get(String namespace, Iterable<Long> interactionIds) {
				
		List<InteractionProp> props = new ArrayList<>();
		
		Map<Long, InteractionEntity> entities = ofy(namespace).load().type(InteractionEntity.class)
				.ids(interactionIds);
		
		for (InteractionEntity entity : entities.values()) {
			if (null != entity)
				props.add(entity.toProp());
		}
		
		Collections.sort(props);				
		return props;
	}
	
	static List<InteractionProp> get(String namespace, long interactionId) {			
		List<Long> interactionIds = new ArrayList<>();
		interactionIds.add(interactionId);
		
		return get(namespace, interactionIds);		
	}
	
	static InteractionProp update(final String namespace, final long interactionId, 
			final String interaction, final InteractionType interactionType, 
			Date timestamp, final long userId) {
		
		safeGet(namespace, interactionId);
		
		if (null == timestamp)
			timestamp = new Date();
		
		ensureValid(interaction, interactionType, timestamp);
		
		final Date ts = timestamp;
		InteractionProp interactionProp = ofy(namespace).transact(new Work<InteractionProp>() {

			@Override
			public InteractionProp run() {
				InteractionEntity interactionEntity = safeGet(namespace, interactionId);
				if (null != interaction)
					interactionEntity.interaction = interaction;
				
				if (null != interactionType)
					interactionEntity.interactionType = interactionType;
								
				interactionEntity.timestamp = ts;
				interactionEntity.userId = userId;
				
				ofy(namespace).save().entity(interactionEntity).now();				
				return interactionEntity.toProp();
			}
		});
		
		return interactionProp;
	}
}
